/**
 * @description 在浏览器渲染的下一帧执行
 * @param {*} callback 在浏览器渲染的下一帧执行的回调函数
 */
const nextFrame = (callback) => {
  requestAnimationFrame(() => {
    requestAnimationFrame(callback);
  });
};

export const Transition = {
  name: "Transition",
  setup(props, { slots }) {
    return () => {
      const innerVNode = slots.default();

      innerVNode.transition = {
        /**
         * @description 添加过渡动画并执行过渡动画，在元素挂载之前执行
         * @param {*} el 需要添加过渡效果的元素
         */
        beforeEnter(el) {
          /* 设置元素进入过渡的初始状态，添加enter-from和enter-active类 */
          el.classList.add("enter-from");
          el.classList.add("enter-active");
        },
        /**
         * @description 移除进入过渡动画，添加离开过渡动画，元素被挂载之后执行
         * @param {*} el 添加过渡效果的元素
         */
        enter(el) {
          nextFrame(() => {
            /* 在浏览器渲染的下一帧，移除过渡的初始状态，添加过渡完成的状态 */
            el.classList.remove("enter-from");
            el.classList.remove("enter-to");
            /* 在过渡完成后将过渡完成状态和过渡的过程移除 */
            el.addEventListener("transitionend", () => {
              el.classList.remove("enter-to");
              el.classList.remove("enter-active");
            });
          });
        },
        /**
         * @description 执行离开过渡动画，元素被卸载之前执行
         * @param {*} el 添加过渡效果的元素
         */
        leave(el, performRemove) {
          /* 添加元素离开过渡的初始状态和过渡的过程类 */
          el.classList.add("leave-from");
          el.classList.add("leave-active");
          /* 强制reflow， 使得初始状态生效 */
          document.body.offsetHeight;
          /* 在下一帧修改过渡状态 */
          nextFrame(() => {
            /* 移除离开过渡的初始状态，添加离开过渡的完成状态 */
            el.classList.remove("leave-from");
            el.classList.add("leave-to");

            /* 监听过渡动画完成事件，在过渡完成后移除过渡的完成状态和过渡过程类 */
            el.addEventListener("transitionend", () => {
              el.classList.remove("leave-to");
              el.classList.remove("leave-active");
              /* 卸载元素 */
              performRemove();
            });
          });
        },
      };

      return innerVNode;
    };
  },
};
